package com.atguigu.gulimall.order.config;

import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import javax.annotation.PostConstruct;

/**
 * @author: kaiyi
 * @create: 2020-09-11 14:21
 */

@Configuration
public class MyRabbitConfig {

  private RabbitTemplate rabbitTemplate;

  @Primary
  @Bean
  public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
    RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
    this.rabbitTemplate = rabbitTemplate;
    rabbitTemplate.setMessageConverter(messageConverter());
    initRabbitTemplate();
    return rabbitTemplate;
  }


  /**
   * 使用JSON序列化机制，进行消息转换
   *
   * @return
   */
  @Bean
  public MessageConverter messageConverter() {
    return new Jackson2JsonMessageConverter();
  }

  /**
   * 定制RabbitTemplate
   * 1、服务收到消息就会回调
   * 1、spring.rabbitmq.publisher-confirms: true
   * 2、设置确认回调
   * 2、消息正确抵达队列就会进行回调
   * 1、spring.rabbitmq.publisher-returns: true
   * spring.rabbitmq.template.mandatory: true
   * 2、设置确认回调ReturnCallback
   * <p>
   * 3、消费端确认(保证每个消息都被正确消费，此时才可以broker删除这个消息)
   */
  // @PostConstruct  //MyRabbitConfig对象创建完成以后，执行这个方法
  public void initRabbitTemplate() {

    /**
     * 1、只要消息抵达Broker就ack=true
     * correlationData：当前消息的唯一关联数据(这个是消息的唯一id)
     * ack：消息是否成功收到
     * cause：失败的原因
     */
    //设置确认回调
    rabbitTemplate.setConfirmCallback((correlationData,ack,cause) -> {
      /**
       * 1、做好消息确认机制（publisher,consumer【手动ack】】）
       * 2、每一个发送的消息都在数据库做好记录。定期将失败的消息再发送一遍
       */
       // 服务器收到了，修改消息的状态
      System.out.println("confirm...correlationData["+correlationData+"]==>ack:["+ack+"]==>cause:["+cause+"]");
    });

    /**
     * 2、只要消息没有投递给指定的队列，就触发这个失败回调
     * message：投递失败的消息详细信息
     * replyCode：回复的状态码
     * replyText：回复的文本内容
     * exchange：当时这个消息发给哪个交换机
     * routingKey：当时这个消息用哪个路邮键
     */
    rabbitTemplate.setReturnCallback((message,replyCode,replyText,exchange,routingKey) -> {
      System.out.println("Fail Message["+message+"]==>replyCode["+replyCode+"]" +
          "==>replyText["+replyText+"]==>exchange["+exchange+"]==>routingKey["+routingKey+"]");
    });

  }



}